//
// Created by root on 24-9-10.
//

#ifndef FACIAL_RECOGNITION_CORE_THREADSAFE_QUEUE_H
#define FACIAL_RECOGNITION_CORE_THREADSAFE_QUEUE_H

#include <queue>
#include <mutex>
#include <condition_variable>

namespace ai::facial_recognition
{

    template <typename T>
    class threadsafe_queue
    {
    private:
        mutable std::mutex mut;
        std::condition_variable not_empty, not_full; // 变量名指示线程不阻塞的条件
        size_t max_sz;
        std::queue<T> data_queue;

    public:
        threadsafe_queue(size_t sz) : max_sz(sz) {}

        bool try_push(T new_value)
        {
            std::lock_guard<std::mutex> lk(mut);
            if (data_queue.size() >= max_sz)
            {
                // printf("data_queue size: %d\n", data_queue.size());
                // remove the first
                data_queue.pop();
                // return false;
            }

            data_queue.push(new_value);
            not_empty.notify_one();

            // printf("After pushed, data_queue size: %d\n", data_queue.size());
            return true;
        }

        void wait_and_push(T new_value)
        {
            std::unique_lock<std::mutex> lk(mut);
            not_full.wait(lk, [this]
                          { return data_queue.size() < max_sz; });
            data_queue.push(new_value);
            not_empty.notify_one();
        }

        bool try_pop(T &value)
        {
            std::lock_guard<std::mutex> lk(mut);
            if (data_queue.empty())
                return false;
            value = data_queue.front();
            data_queue.pop();
            not_full.notify_one();
            return true;
        }

        std::shared_ptr<T> try_pop()
        {
            std::lock_guard<std::mutex> lk(mut);
            if (data_queue.empty())
                return false;
            std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
            data_queue.pop();
            not_full.notify_one();
            return res;
        }

        void wait_and_pop(T &value)
        {
            std::unique_lock<std::mutex> lk(mut);
            not_empty.wait(lk, [this]
                           { return !data_queue.empty(); });
            value = data_queue.front();
            data_queue.pop();
            not_full.notify_one();
        }

        std::shared_ptr<T> wait_and_pop()
        {
            std::unique_lock<std::mutex> lk(mut);
            not_empty.wait(lk, [this]
                           { return !data_queue.empty(); });
            std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
            data_queue.pop();
            not_full.notify_one();
            return res;
        }

        bool empty() const
        {
            std::lock_guard<std::mutex> lk(mut);
            return data_queue.empty();
        }

        int get_size()
        {
            std::lock_guard<std::mutex> lk(mut);
            return data_queue.size();
        }
    };

}

#endif // FACIAL_RECOGNITION_CORE_THREADSAFE_QUEUE_H
